#include "general.h"
#include <libbuolaIO.h>

#include "sql_bind.h"

#include <buolabase_basicio.h>
#include <cfolder.h>

void CDataServer::ReadMetadata()
{
    while(mQueries.mGetMetadata->Step())
    {
        SMetadata *lMetadata=new SMetadata;
        lMetadata->mID=mQueries.mGetMetadata->ExtractInt(0);
        lMetadata->mName=mQueries.mGetMetadata->ExtractByteString(1);
        lMetadata->mType=mQueries.mGetMetadata->ExtractInt(2);
        lMetadata->mMultiple=mQueries.mGetMetadata->ExtractInt(3);
        lMetadata->mWeight=mQueries.mGetMetadata->ExtractInt(4);
        
        mCache.mMetadataByID[lMetadata->mID]=lMetadata;
        mCache.mMetadataByName[lMetadata->mName]=lMetadata;
    }
    mQueries.mGetMetadata->Reset();
}

CDataServer::SMetadata *CDataServer::AddMetadata(const std::string &pName,
                                int pType,bool pMultiple,int pWeight)
{
    SMetadata *lMetadata=new SMetadata;
    lMetadata->mName=pName;
    lMetadata->mType=pType;
    lMetadata->mMultiple=pMultiple;
    lMetadata->mWeight=pWeight;

    mQueries.mInsertMetadata->BindByteString(BIND_INSERT_METADATA_NAME,pName);
    mQueries.mInsertMetadata->BindInt(BIND_INSERT_METADATA_TYPE,pType);
    mQueries.mInsertMetadata->BindInt(BIND_INSERT_METADATA_MULTIPLE,pMultiple?1:0);
    mQueries.mInsertMetadata->BindInt(BIND_INSERT_METADATA_WEIGHT,pWeight);
    mQueries.mInsertMetadata->Exec();
    mQueries.mInsertMetadata->Reset();
    
    lMetadata->mID=mDB->GetLastInsertID();  

    mCache.mMetadataByID[lMetadata->mID]=lMetadata;
    mCache.mMetadataByName[lMetadata->mName]=lMetadata;
    
    return lMetadata;
}

CDataServer::SMetadata *CDataServer::GetMetadataType(
                                const std::string &pMetadata,bool pCreate)
{
    SMetadata *lMetadata=mCache.mMetadataByName.count(pMetadata)?
                mCache.mMetadataByName[pMetadata]:nullptr;
    
    if(!lMetadata&&pCreate)
    {
        lMetadata=AddMetadata(pMetadata,METADATA_TYPE_STRING,false,0);
    }
    
    return lMetadata;
}

TID CDataServer::GetFolderID(const std::string &pFolder,bool pCreate)
{
    TID lID=0;

    mQueries.mGetFolderID->BindByteString(BIND_GET_FOLDER_FULLPATH,pFolder);
    
    while(mQueries.mGetFolderID->Step())
    {
        lID=mQueries.mGetFolderID->ExtractInt(0);
    }
    mQueries.mGetFolderID->Reset();
    
    if(!lID&&pCreate)
    {
        mQueries.mInsertFolder->BindByteString(BIND_INSERT_FOLDER_FULLPATH,pFolder);
        mQueries.mInsertFolder->Exec();
        mQueries.mInsertFolder->Reset();
        lID=mDB->GetLastInsertID();
    }
    
    return lID;
}

TID CDataServer::GetObjectID(TID pFolderID,const std::string &pName,bool pCreate)
{
    TID lID=0;

    mQueries.mGetObjectID->BindInt(BIND_GET_OBJECT_FOLDERID,pFolderID);
    mQueries.mGetObjectID->BindByteString(BIND_GET_OBJECT_NAME,pName);
    
    while(mQueries.mGetObjectID->Step())
    {
        lID=mQueries.mGetObjectID->ExtractInt(0);
    }
    mQueries.mGetObjectID->Reset();
    
    if(!lID&&pCreate)
    {
        mQueries.mInsertObject->BindInt(BIND_INSERT_OBJECT_FOLDERID,pFolderID);
        mQueries.mInsertObject->BindByteString(BIND_INSERT_OBJECT_NAME,pName);

        mQueries.mInsertObject->Exec();
        mQueries.mInsertObject->Reset();
        lID=mDB->GetLastInsertID();
    }
    
    return lID;
}

std::string CDataServer::GetObjectMime(TID pFolderID,const std::string &pName)
{
    std::string lMime;

    mQueries.mGetObject->BindInt(BIND_GET_OBJECT_FOLDERID,pFolderID);
    mQueries.mGetObject->BindByteString(BIND_GET_OBJECT_NAME,pName);
    
    while(mQueries.mGetObject->Step())
    {
        lMime=mQueries.mGetObject->ExtractByteString(3);
    }
    mQueries.mGetObject->Reset();
    
    return lMime;
}

TID CDataServer::InsertObject(TID pFolderID,const std::string &pName,
        const std::string &pMIME,int pFileSize,bool pIsFolder,bool pIsLink,
        int pTime)
{
    mQueries.mInsertObject->BindInt(BIND_INSERT_OBJECT_FOLDERID,pFolderID);
    mQueries.mInsertObject->BindByteString(BIND_INSERT_OBJECT_NAME,pName);
    mQueries.mInsertObject->BindByteString(BIND_INSERT_OBJECT_MIME,pMIME);
    mQueries.mInsertObject->BindInt(BIND_INSERT_OBJECT_FILESIZE,pFileSize);
    mQueries.mInsertObject->BindInt(BIND_INSERT_OBJECT_ISFOLDER,pIsFolder?1:0);
    mQueries.mInsertObject->BindInt(BIND_INSERT_OBJECT_ISLINK,pIsLink?1:0);
    mQueries.mInsertObject->BindInt(BIND_INSERT_OBJECT_CHECKTIME,pTime);

    mQueries.mInsertObject->Exec();
    mQueries.mInsertObject->Reset();
    mQueries.mInsertObject->ResetBindings();

    return mDB->GetLastInsertID();
}

void CDataServer::GetMimeTypes(const std::string &pFolder,dbus::CReply *pReply)
{
    CURL lURL(pFolder);
    PFolder lFolder=CFolder::Get(pFolder);
    
    TID lFolderID=GetFolderID(pFolder,true);

    std::vector<PFile> lFiles;
    
    lFolder->GetAll(lFiles);
    
    pReply->OpenArray(DBUSTYPE_STRUCT(DBUSTYPE_INT DBUSTYPE_STRING DBUSTYPE_STRING));
    for(int i=0;i<lFiles.size();i++)
    {
//      msg_info() << lFiles[i]->GetURL() << "\n";
//      CMIMEType *lType=CMIMEType::Get(lFiles[i]);
//      msg_info() << lFiles[i]->GetURL() << " -> " << lType->GetMIME() << "\n";
//      InsertObject(lFolderID,lFiles[i]->GetURL().GetName(),lType->GetMIME(),
//                  lFiles[i]->GetSize(),lFiles[i]->IsFolder(),
//                  lFiles[i]->IsLink(),lFiles[i]->GetMTime().GetInt());
//      msg_debug<25>() << "Time=" << lFiles[i]->GetMTime().GetInt() << "\n";
        pReply->OpenContainer();
        pReply->Append(lFolderID);
        std::string lType=GetObjectMime(lFolderID,lFiles[i]->GetURL().GetName());
        pReply->Append(lFiles[i]->GetURL().GetName());
        pReply->Append(lType);
        pReply->CloseContainer();
    }
    pReply->CloseContainer();
}

void CDataServer::SetMetadata(const std::string &pFolder,const std::string &pName,
                              const std::string &pKey,const UValue &pValue)
{
    TID lFolderID=GetFolderID(pFolder,true);
    TID lObjectID=GetObjectID(lFolderID,pName,true);
    SMetadata *lMetadata=GetMetadataType(pKey,true);
    
    mQueries.mInsertObjectMetadata->BindInt(BIND_INSERT_OBJECTMETADATA_OBJECTID,lObjectID);
    mQueries.mInsertObjectMetadata->BindInt(BIND_INSERT_OBJECTMETADATA_METADATAID,lMetadata->mID);
    mQueries.mInsertObjectMetadata->BindString(BIND_INSERT_OBJECTMETADATA_VALUE,pValue.ToString());
    mQueries.mInsertObjectMetadata->Exec();
    mQueries.mInsertObjectMetadata->Reset();
}

void CDataServer::GetMetadata(const std::string &pFolder,const std::string &pName,
                              const std::string &pKey,UValue &pValue)
{
    SMetadata *lMetadata=GetMetadataType(pKey,false);
    
    if(!lMetadata) return;
    
    mQueries.mGetObjectMetadata->BindByteString(1,pFolder);
    mQueries.mGetObjectMetadata->BindByteString(2,pName);
    mQueries.mGetObjectMetadata->BindInt(3,lMetadata->mID);
    while(mQueries.mGetObjectMetadata->Step())
    {
        pValue=UValue(nFromString,mQueries.mGetObjectMetadata->ExtractString(0));
    }
    mQueries.mGetObjectMetadata->Reset();
}
